C# Type | SQL Server Type | Size | Range |
---|---|---|---|
byte |
TINYINT |
1 byte | 0 to 255 |
short |
SMALLINT |
2 bytes | -32,768 to 32,767 |
int |
INT |
4 bytes | -2,147,483,648 to 2,147,483,647 |
long |
BIGINT |
8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
❗ Important Notes:
SMALLINT
and TINYINT
save space, but be careful about hitting the limit.BIGINT
is needed only if you expect billions of records.Field | Recommended C# Type | SQL Server Type | Why? |
---|---|---|---|
UserId |
int or long |
INT or BIGINT |
INT is usually enough unless expecting billions of users. |
TicketId |
int or long |
INT or BIGINT |
Use BIGINT if expecting massive ticket volumes. |
GenderId |
byte or short |
TINYINT or SMALLINT |
Gender options are limited, so TINYINT is sufficient. |
CompanyId |
int |
INT |
Companies are limited, INT is fine. |
VehicleId |
int |
INT |
Use INT , as vehicle count is manageable. |
Price |
decimal(18,2) |
DECIMAL(18,2) |
Avoid float /double due to rounding issues. |
GUID
(UNIQUEIDENTIFIER
) for IDs only if:
int
or long
for performance.📌 Example in C# (EF Core Model):
public class Ticket
{
public int TicketId { get; set; } // Primary key
public int UserId { get; set; } // Foreign key
public decimal Price { get; set; } // Use decimal for money
public DateTime PurchaseDate { get; set; }
}
📌 Fluent API (SQL Mapping)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Ticket>()
.Property(t => t.Price)
.HasColumnType("DECIMAL(18,2)");
}
required
keyword (Chat GPT) :C# IntelliSense suggests adding required
to string properties because of nullable reference types (NRT) introduced in C# 8.0+.
required
Do?required
forces initialization of the property when creating an object.[Required]
in EF Core), but a C# keyword that affects compile-time checks.📌 Example Without required
public class User
{
public string Name { get; set; } // Warning: "Non-nullable property 'Name' is uninitialized"
}
🔴 Problem: The compiler warns that Name
is not initialized.
✅ Fix: Add required
or initialize the property.
📌 Example With required
public class User
{
public required string Name { get; set; } // No warning
}
✅ Effect: You must provide Name
when creating a User
object.
var user = new User { Name = "Mehrdad" }; // ✅ Works
var invalidUser = new User(); // ❌ Compilation Error: Name is required
string
is nullable in C#, but in nullable reference types (C# 8+), string
is treated as non-nullable unless explicitly marked string?
.
string
→ Default behavior (non-nullable by default in nullable context).string?
→ Explicitly nullable.virtual
, EF Core creates a proxy class at runtime that overrides the property and loads related data only when accessed.virtual
, you must load relationships using .Include()
(Eager Loading).Scenario | Recommended Type | Why? |
---|---|---|
Single reference (e.g., Ticket → Transportation ) |
virtual Transportation |
Represents a one-to-one or many-to-one relationship. |
Collection of related entities (e.g., Transportation → Tickets ) |
virtual ICollection<Ticket> |
Best for one-to-many relationships, supports lazy loading. |
Alternative for collections | virtual List<Ticket> |
Works the same, but EF prefers ICollection<T> . |
Using IEnumerable<T> |
❌ Avoid | EF does not recognize IEnumerable<T> for navigation properties. |
The N+1 query problem happens when EF Core makes too many separate database queries instead of loading data efficiently.
Let’s say you have 100 tickets, and each ticket has a related Transportation entity.
You run this code:
var tickets = context.Tickets.ToList(); // Loads all tickets foreach (var ticket in tickets)
{
Console.WriteLine(ticket.Transportation.Name); // Lazy loads Transportation for each ticket
}
Tickets
.Transportation
(so 100 additional queries).